JS - Promises
Home

JS - Promises

JS - Promises

Tot en met ES5 was het mechanisme van de functie callback de belangrijkste manier voor het beheer van asynchronie in JavaScript. In ES6 beschikken we over een nieuw mechanisme, namelijk promises waarmee enkele in het oogspringend tekortkomingen van de callbacks-only benadering van het asynchrone opgelost worden.

Inleiding

Promises zijn er niet om callbacks te vervangen. Promises bieden een betrouwbare tussenpersoon (proxy) tussen de de code die de promise aanroept en de asynchrone code die de taak in de toekomst zal uitvoeren om callbacks te beheren.

Promises kunnen aan elkaar worden geketend (chained), waarmee een reeks van asychronoon te voltooien stappen gepland kan worden.

Een Promise is een belofte, het is een toekomstige waarde, een time-onafhankelijke container die rond een waarde wordt gewikkeld. Je moet over deze container op identieke wijze nadenken los van de vraag of de onderliggende waarde definitief is of niet. Het observeren van de vervulling van een promise haalt de deze waarde op zodra ze beschikbaar is. Met andere woorden, van een Promise wordt gezegd dat ze de asynchrone versie is van een sync functie's return waarde.

Een Promise kan slechts één van de twee mogelijke resolutie uitkomsten hebben:

  1. vervuld of
  2. afgewezen, met een optionele enkele waarde.

Als een Promise wordt nagekomen, wordt eindwaarde een vervulling (fullfillment) genoemd. Als de Promise wordt afgewezen, wordt de uiteindelijke waarde een reden (reason) genoemd (zoals bij een "reden voor afwijzing"). Promises kunnen slechts eenmalig opgelost worden (vervulling of afwijzing). Elke verdere poging om de Promise te vervullen of af te wijzen wordt genegeerd. Dat wil zeggen dat eens een Promise opgelost is, het een onveranderlijke waarde is die niet meer kan worden gewijzigd.

Het is duidelijk dat er verschillende manieren zijn om na te denken over wat een Promise is. Geen enkel perspectief volstaat. Maar Promises zijn in elk geval een aanzienlijke verbetering ten opzichte van callbacks-only async, namelijk ze bieden orde, voorspelbaarheid en betrouwbaarheid.

Een Promise maken en gebruiken

Om een instantie van een Promise te maken gebruikt je de Promise() constructor:

var p = new Promise( function(resolve,reject){
    // ..
} );

De twee opgegeven parameters in de Promise() constructor zijn functies en worden meestal resolve() en reject() genoemd. Ze worden als volgt gebruikt:

Hier volgt een eenvoudig voorbeeld. De variabele done staat ingesteld op false. Normaal gezien zet je hier code die een toekomstige handeling evalueert. Verander de waarde van done en stel die in op true.

<!--
JavaScript Promises There and back again
By Jake Archibald
Published: December 16th, 2013
Updated: September 26th, 2016
http://www.html5rocks.com/en/tutorials/es6/promises/
-->
<!doctype html>
<html lang="nl">

<head>
    <meta charset="UTF-8">
    <title>Promises</title>
    <script>
        /* JavaScript Promises There and back again
        By Jake Archibald
        Published: December 16th, 2013
        Updated: September 26th, 2016
        http://www.html5rocks.com/en/tutorials/es6/promises/
        */
        var alsHetWerkt = new Promise(function(resolve, reject) {
            // do a thing, possibly async, then…
            var done = false;

            /* everything turned out fine */
            if (done) {
                resolve("Het werkt!");
            }
            else {
                reject(Error("Het werkt niet..."));
            }
        });
        alsHetWerkt.then(
            function(result) {
                /* als het werkt doe dit */
                console.log(result); // "Het werkt!"
            }, 
            function(err) {
                /* anders doe dat */  
                console.log(err.message, err.name); // "Het werkt niet..."
            }
        );
    </script>
</head>
<body>
</body>
</html>

In het voorbeeld hierboven maken gebruik van het JavaScript Error Object. Meer info op MDN, Error.

then

Alle instanties van Promise beschikken over een then methode waarmee je kan reageren om het vervullen of afwijzen van de 'belofte'. De eerste then callback methode krijgt als argument de retourwaarde van de resolve() methode mee:

var p = new Promise(function(resolve, reject) {
  // A mock async action using setTimeout
  setTimeout(function() {
    resolve('er zijn 2 seconden verlopen');
  }, 2000);
});

p.then(function(result) {
  console.log(result);
});

De then callback wordt afgevuurd als de belofte vervuld is.

Je kan de then methode aaneenschakelen:

var p2 = new Promise(function(resolve, reject) {
  // A mock async action using setTimeout
  setTimeout(function() {
    resolve('er zijn 4 seconden verlopen');
  }, 4000);
});

p2.then(function(result) {
  console.log('then 1:', result);
  return 'na 4 sec belofte vervuld, bewerkt en doorgegeven 2de then';
}).then(function(result) {
  console.log('then 2', result);
  return 'resultaat van 1ste then door 2de then bewerkt en doorgegeven';
}).then (function(result) {
  console.log('then 3', result);});

Elke then methode krijgt de retourwaarde van de vorige then mee. Als een belofte vervuld is en then wordt opnieuw opgeroepen wordt de callback onmiddellijk uitgevoerd. Als de belofte afgewezen wordt en je roep then op na de afwijzing wordt de callback nooit uitgevoerd.

catch

De catch callback methode wordt uitgevoerd als de promise verworpen wordt. Wat je meegeeft bepaal je zef. Een veel voorkomend patroon is het gebruik van het JavaScript Error Object. Meer info op MDN, Error.

HTML

<h1>Promises: de <code>catch</code> methode</h1>
<p style="color: red">Open het Console venster (links onder) om met deze Pen te werken!</p>
<div>
  <p>klik binnen de 5 seconden op akkood!!!</p>
  <input type=checkbox id="akkoord"/>
  <label for="akkoord">akkoord </label>
</div>

JS

var p = new Promise(function(resolve, reject) {
  // A mock async action using setTimeout
  setTimeout(function() {
    var akkoord = document.getElementById('akkoord').checked;
    if (akkoord) {
      resolve('Je hebt tijdig onze voorwaarden aanvaard!');
    } else {
      reject(Error('Je hebt niet tijdig onze voorwaarden aanvaard!'));
    }
  }, 5000);
});

p.then(function(result) {
  console.log(result);
}).catch(function(result) {
  console.log(result.message);
});

Bronnen

  1. Kyle Simpson, You Don’t Know JS: ES6 & Beyond, O’Reilly, 2016
  2. David Walsh, JavaScript Promise API, november 2, 2015
  3. Jecelyn Yeen, JavaScript Promises for Dummies, Get to know JavaScript Promises better, Dec 01, 2016
  4. JavaScript Kit, Beginner's Guide to JavaScript promises, Sept 21st, 2015

JI
2021-03-24 16:50:03